﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Web.Security;
using System.Security.Cryptography;
using System.Configuration;
using SAKS.IServices;
using SAKS.Models;
using SAKS.ConfigManager;
using NHibernate;
using NHibernate.Linq;
using System.Collections.Specialized;

namespace SAKS.Services
{
    public class MembershipServices : IMembershipServices
    {

        private ISession _session;
        public ISession Session 
        {
            get { return _session; }
            set
            {
                _session = value;
            }
        }


        public bool IsUserExist(string username)
        {
            return Session.Query<User>().Where(u => u.UserName == username).Count() >= 1;
        }

        public bool ValidateUser(string userName, string password)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("值不可以为空或\"null\".", "userName");
            if (String.IsNullOrEmpty(password)) throw new ArgumentException("值不可以为空或\"null\".", "password");

            User user = Session.QueryOver<User>().Where(u => u.UserName == userName).SingleOrDefault() ;
            if (user == null)
                return false;

            string encryptedPassword = PasswordEncrypter.Encrypt(password, user.Membership.PasswordFormat, user.Membership.PasswordSalt);
            return encryptedPassword == user.Membership.Password;
        }


        public MembershipCreateStatus CreateUser(string userName, string password, string email)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("值不可以为空或\"null\".", "userName");
            if (String.IsNullOrEmpty(password)) throw new ArgumentException("值不可以为空或\"null\".", "password");
            if (String.IsNullOrEmpty(email)) throw new ArgumentException("值不可以为空或\"null\".", "email");
            if (IsUserExist(userName)) return MembershipCreateStatus.DuplicateUserName;
            var user = UserBuilder.Build(UserName : userName);
            var membership = MembershipBuilder.Build(Password: password, Email: email);
            membership.User = user;
            user.Membership = membership;
            Session.Save(user);
            return MembershipCreateStatus.Success;
        }

        public bool ChangePassword(string userName, string oldPassword, string newPassword)
        {
            if (String.IsNullOrEmpty(userName)) throw new ArgumentException("值不可以为空或\"null\".", "userName");
            if (String.IsNullOrEmpty(oldPassword)) throw new ArgumentException("值不可以为空或\"null\".", "oldPassword");
            if (String.IsNullOrEmpty(newPassword)) throw new ArgumentException("值不可以为空或\"null\".", "newPassword");

            // The underlying ChangePassword() will throw an exception rather
            // than return false in certain failure scenarios.
            try
            {
                if (ValidateUser(userName, oldPassword))
                {
                    var membership = Session.QueryOver<User>().Where(u => u.UserName == userName).SingleOrDefault().Membership;
                    var newSalt = SaltGenerator.Generate();
                    var newPass = PasswordEncrypter.Encrypt(newPassword, MembershipConfig.PassworFormat, newSalt);
                    membership.Password = newPass;
                    membership.PasswordSalt = newSalt;
                    membership.PasswordFormat = MembershipConfig.PassworFormat;
                    Session.SaveOrUpdate(membership);
                    return true;
                }
                else
                    return false;

            }
            catch (ArgumentException)
            {
                return false;
            }
            catch (MembershipPasswordException)
            {
                return false;
            }
        }

        
    }

    public static class UserBuilder
    {
        public static User Build(string UserName = "", bool IsAnonymous = false)
        {
            return new User
            {
                UserName = UserName,
                LoweredUserName = UserName.ToLower(),
                IsAnonymous = IsAnonymous,
                LastActivityDate = DateTime.Now
            };
        }
    }


    public static class MembershipBuilder
    {
        public static SAKS.Models.Membership Build(string Email = null, string Password = "")
        {
            var salt = SaltGenerator.Generate();
            return new SAKS.Models.Membership
            {
                PasswordFormat = MembershipConfig.PassworFormat,
                Password = PasswordEncrypter.Encrypt(Password, MembershipConfig.PassworFormat, salt),
                PasswordSalt = salt,
                CreateDate = DateTime.Now,
                Email = Email,
                LoweredEmail = Email.ToLower(),
                LastLoginDate = DateTime.Now,
                LastPasswordChangedDate = DateTime.Now,

            };
        }
    }

    public static class SaltGenerator
    {
        public static string Generate()
        {
            byte[] data = new byte[0x10];
            new RNGCryptoServiceProvider().GetBytes(data);
            return Convert.ToBase64String(data);
        }
    }


    public static class PasswordEncrypter
    {
        public static string Encrypt(string pass, PasswordFormat passwordFormat, string salt)
        {
            if (passwordFormat == PasswordFormat.Clear)
            {
                return pass;
            }


            byte[] bytes = Encoding.Unicode.GetBytes(pass);
            byte[] src = Convert.FromBase64String(salt);
            byte[] inArray = null;


            var hashAlgorithm = GetHashAlgorithm(passwordFormat);
            if (hashAlgorithm is KeyedHashAlgorithm)
            {
                KeyedHashAlgorithm algorithm2 = (KeyedHashAlgorithm)hashAlgorithm;
                if (algorithm2.Key.Length == src.Length)
                {
                    algorithm2.Key = src;
                }
                else if (algorithm2.Key.Length < src.Length)
                {
                    byte[] dst = new byte[algorithm2.Key.Length];
                    Buffer.BlockCopy(src, 0, dst, 0, dst.Length);
                    algorithm2.Key = dst;
                }
                else
                {
                    int num2;
                    byte[] buffer5 = new byte[algorithm2.Key.Length];
                    for (int i = 0; i < buffer5.Length; i += num2)
                    {
                        num2 = Math.Min(src.Length, buffer5.Length - i);
                        Buffer.BlockCopy(src, 0, buffer5, i, num2);
                    }
                    algorithm2.Key = buffer5;
                }
                inArray = algorithm2.ComputeHash(bytes);
            }
            else
            {
                byte[] buffer6 = new byte[src.Length + bytes.Length];
                Buffer.BlockCopy(src, 0, buffer6, 0, src.Length);
                Buffer.BlockCopy(bytes, 0, buffer6, src.Length, bytes.Length);
                inArray = hashAlgorithm.ComputeHash(buffer6);
            }

            return Convert.ToBase64String(inArray);
        }

        private static HashAlgorithm GetHashAlgorithm(PasswordFormat passwordFormat)
        {
            return HashAlgorithm.Create(passwordFormat.ToString());
        }
    }

}
